#####################################################################
#
# WEB APP FOR RFID READER SDK
# AUTHOR: zengkai001@qq.com
# DATE: 2025-01-24
#
#####################################################################

import sys
import time
import os
import logging
from logging.handlers import TimedRotatingFileHandler, RotatingFileHandler
from pathlib import Path
from flask import Flask, render_template, request, redirect, flash, jsonify
from flask_cors import CORS
import traceback

# Configure logging
def setup_logging():
    # Create logs directory if it doesn't exist
    log_dir = Path(__file__).parent / 'logs'
    log_dir.mkdir(exist_ok=True)
    log_file = log_dir / 'app.log'

    # Create formatters
    file_formatter = logging.Formatter(
        '%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d - %(funcName)s - %(message)s'
    )
    console_formatter = logging.Formatter(
        '%(asctime)s - %(levelname)s - %(message)s'
    )

    # Set up file handler with both time and size based rotation
    file_handler = TimedRotatingFileHandler(
        log_file,
        when='midnight',
        interval=1,
        backupCount=30,
    )
    file_handler.setLevel(logging.DEBUG)
    file_handler.setFormatter(file_formatter)

    # Add size based rotation
    size_handler = RotatingFileHandler(
        log_file,
        maxBytes=20*1024*1024,  # 20MB
        backupCount=5
    )
    size_handler.setLevel(logging.DEBUG)
    size_handler.setFormatter(file_formatter)

    # Set up console handler
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.INFO)
    console_handler.setFormatter(console_formatter)

    # Configure root logger
    root_logger = logging.getLogger()
    root_logger.setLevel(logging.DEBUG)
    root_logger.addHandler(file_handler)
    root_logger.addHandler(size_handler)
    root_logger.addHandler(console_handler)

    return root_logger

# Initialize logging
logger = setup_logging()

# Add PYTHON_SDK to path
sys.path.append(str(Path(__file__).parent.parent / 'PYTHON_SDK'))
from rfid_reader import RFIDReader

# Global reader instance
reader = None

app = Flask(__name__)
app.secret_key = 'dev'  # Required for flash messages
CORS(app, resources={
    r"/*": {
        "origins": "*",
        "methods": ["GET", "POST", "OPTIONS"],
        "allow_headers": ["Content-Type"]
    }
})

@app.route('/')
def rfid():
    logger.info("Rendering main RFID page")
    return render_template('rfid.html')

@app.route('/open-device', methods=['POST'])
def open_device():
    global reader
    logger.info("Attempting to open RFID device")
    try:
        if reader is not None:
            logger.warning("Device is already open")
            return {
                'error': True,
                'message': "Device is already open"
            }
            
        # Initialize reader with library path
        lib_path = str(Path(__file__).parent.parent / 'PYTHON_SDK/x86_64/libGZAE_rfid.so')
        logger.debug(f"Initializing reader with library path: {lib_path}")
        reader = RFIDReader(lib_path)
        
        # Open connection (using default connection string)
        conn_string = "RDType=RL8000;CommType=USB;AddrMode=0;SerNum="
        logger.debug(f"Opening device with connection string: {conn_string}")
        reader.open_device(conn_string)
        
        logger.info("Device opened successfully")
        return {
            'error': False,
            'message': "Device opened successfully"
        }
    except Exception as e:
        logger.error(f"Error opening device: {str(e)}", exc_info=True)
        return {
            'error': True,
            'message': f"Error opening device: {str(e)}"
        }

@app.route('/device-info', methods=['POST'])
def device_info():
    global reader
    logger.info("Requesting device info")
    try:
        if reader is None:
            logger.warning("Device not opened")
            return {
                'error': True,
                'message': "Device not opened. Please open device first."
            }
        
        # Get device info
        logger.debug("Getting device info")
        info = reader.get_device_info()
        logger.info(f"Successfully retrieved device info: {info}")
        return {
            'error': False,
            'message': f"Device Info: {info}"
        }
    except Exception as e:
        logger.error(f"Error getting device info: {str(e)}", exc_info=True)
        return {
            'error': True,
            'message': f"Error getting device info: {str(e)}"
        }

@app.route('/close-device', methods=['POST'])
def close_device():
    global reader
    logger.info("Attempting to close device")
    try:
        if reader is None:
            logger.warning("Device is not open")
            return {
                'error': True,
                'message': "Device is not open"
            }
            
        reader.close_device()
        reader = None
        logger.info("Device closed successfully")
        return {
            'error': False,
            'message': "Device closed successfully"
        }
    except Exception as e:
        logger.error(f"Error closing device: {str(e)}", exc_info=True)
        return {
            'error': True,
            'message': f"Error closing device: {str(e)}"
        }

@app.route('/get-tags-info', methods=['POST'])
def get_tags_info():
    global reader
    logger.info("Requesting tags info")
    try:
        if reader is None:
            logger.warning("Device not opened")
            return {
                'error': True,
                'message': "Device not opened. Please open device first."
            }
        
        # Start inventory and wait for results
        logger.debug("Starting inventory")
        reader.start_inventory()
        time.sleep(1)  # Wait for inventory to complete
        
        # Get tag info
        logger.debug("Getting tag info")
        tags = reader.get_tag_info()
        logger.info(f"Successfully retrieved {len(tags) if tags else 0} tags")
        return {
            'error': False,
            'tags': tags
        }
    except Exception as e:
        logger.error(f"Error getting tag info: {str(e)}", exc_info=True)
        return {
            'error': True,
            'message': f"Error getting tag info: {str(e)}"
        }

@app.route('/read-tag', methods=['POST'])
def read_tag():
    global reader
    logger.info("Attempting to read tag")
    try:
        if reader is None:
            logger.warning("Device not opened")
            return {
                'error': True,
                'message': "Device not opened. Please open device first."
            }
            
        # Get parameters from request
        data = request.get_json()
        uid = data.get('uid')
        block_start = int(data.get('blockStart', 0))
        block_count = int(data.get('blockCount', 1))
        
        logger.debug(f"Reading tag - UID: {uid}, Block Start: {block_start}, Block Count: {block_count}")
        
        if not uid:
            logger.warning("UID is required but not provided")
            return {
                'error': True,
                'message': "UID is required"
            }
            
        # Read tag data and convert bytes to hex string
        tag_data = reader.read_tag(uid, block_start, block_count)
        if tag_data is None:
            logger.error("Failed to read tag data")
            return {
                'error': True,
                'message': "Failed to read tag data"
            }
            
        # Convert bytes to hex string for JSON serialization
        tag_data_hex = tag_data.hex()
        logger.info(f"Successfully read tag data from UID: {uid}")
        logger.debug(f"Tag data (hex): {tag_data_hex}")
        return {
            'error': False,
            'data': tag_data_hex
        }
    except Exception as e:
        logger.error(f"Error reading tag data: {str(e)}", exc_info=True)
        return {
            'error': True,
            'message': f"Error reading tag data: {str(e)}"
        }

@app.route('/write-tag', methods=['POST'])
def write_tag():
    global reader
    logger.info("Attempting to write tag")
    try:
        if reader is None:
            logger.warning("Device not opened")
            return {
                'error': True,
                'message': "Device not opened. Please open device first."
            }
            
        # Get parameters from request
        data = request.get_json()
        uid = data.get('uid')
        block_start = int(data.get('blockStart', 0))
        block_count = int(data.get('blockCount', 1))
        tag_data = data.get('tagData')
        
        logger.debug(f"Writing tag - UID: {uid}, Block Start: {block_start}, Block Count: {block_count}, Data: {tag_data}")
        
        if not uid:
            logger.warning("UID is required but not provided")
            return {
                'error': True,
                'message': "UID is required"
            }
        if not tag_data:
            logger.warning("Tag data is required but not provided")
            return {
                'error': True,
                'message': "Tag data is required"
            }
            
        # Write to tag
        result = reader.write_tag(uid, block_start, block_count, tag_data)
        if result is None:
            logger.error("Failed to write tag data")
            return {
                'error': True,
                'message': "Failed to write tag data"
            }
            
        logger.info(f"Successfully wrote data to tag with UID: {uid}")
        return {
            'error': False,
            'message': "Tag data written successfully"
        }
    except Exception as e:
        logger.error(f"Error writing tag data: {str(e)}", exc_info=True)
        return {
            'error': True,
            'message': f"Error writing tag data: {str(e)}"
        }

@app.route('/enable-eas', methods=['POST'])
def enable_eas():
    global reader
    logger.info("Attempting to enable EAS")
    try:
        if reader is None:
            logger.warning("Device not opened")
            return {
                'error': True,
                'message': "Device not opened. Please open device first."
            }
            
        # Get UID from request
        data = request.get_json()
        uid = data.get('uid')
        
        logger.debug(f"Enabling EAS for UID: {uid}")
        
        if not uid:
            logger.warning("UID is required but not provided")
            return {
                'error': True,
                'message': "UID is required"
            }
            
        # Enable EAS
        result = reader.enable_eas(uid)
        if result is None:
            logger.error("Failed to enable EAS")
            return {
                'error': True,
                'message': "Failed to enable EAS"
            }
            
        logger.info(f"Successfully enabled EAS for UID: {uid}")
        return {
            'error': False,
            'message': "EAS enabled successfully"
        }
    except Exception as e:
        logger.error(f"Error enabling EAS: {str(e)}", exc_info=True)
        return {
            'error': True,
            'message': f"Error enabling EAS: {str(e)}"
        }

@app.route('/disable-eas', methods=['POST'])
def disable_eas():
    global reader
    logger.info("Attempting to disable EAS")
    try:
        if reader is None:
            logger.warning("Device not opened")
            return {
                'error': True,
                'message': "Device not opened. Please open device first."
            }
            
        # Get UID from request
        data = request.get_json()
        uid = data.get('uid')
        
        logger.debug(f"Disabling EAS for UID: {uid}")
        
        if not uid:
            logger.warning("UID is required but not provided")
            return {
                'error': True,
                'message': "UID is required"
            }
            
        # Disable EAS
        result = reader.disable_eas(uid)
        if result is None:
            logger.error("Failed to disable EAS")
            return {
                'error': True,
                'message': "Failed to disable EAS"
            }
            
        logger.info(f"Successfully disabled EAS for UID: {uid}")
        return {
            'error': False,
            'message': "EAS disabled successfully"
        }
    except Exception as e:
        logger.error(f"Error disabling EAS: {str(e)}", exc_info=True)
        return {
            'error': True,
            'message': f"Error disabling EAS: {str(e)}"
        }

@app.route('/check-eas', methods=['POST'])
def check_eas():
    global reader
    logger.info("Checking EAS status")
    try:
        if reader is None:
            logger.warning("Device not opened")
            return {
                'error': True,
                'message': "Device not opened. Please open device first."
            }
            
        # Get UID from request
        data = request.get_json()
        uid = data.get('uid')
        
        logger.debug(f"Checking EAS status for UID: {uid}")
        
        if not uid:
            logger.warning("UID is required but not provided")
            return {
                'error': True,
                'message': "UID is required"
            }
            
        # Check EAS status
        status = reader.check_eas(uid)
        if status is None:
            logger.error("Failed to check EAS status")
            return {
                'error': True,
                'message': "Failed to check EAS status"
            }
            
        logger.info(f"Successfully checked EAS status for UID: {uid}, Status: {status}")
        return {
            'error': False,
            'status': status,
            'message': "EAS checked successfully"
        }
    except Exception as e:
        logger.error(f"Error checking EAS status: {str(e)}", exc_info=True)
        return {
            'error': True,
            'message': f"Error checking EAS status: {str(e)}"
        }

@app.route('/write-afi', methods=['POST'])
def write_afi():
    global reader
    logger.info("Attempting to write AFI")
    try:
        if reader is None:
            logger.warning("Device not opened")
            return {
                'error': True,
                'message': "Device not opened. Please open device first."
            }
            
        # Get parameters from request
        data = request.get_json()
        uid = data.get('uid')
        afi = data.get('afi')
        
        logger.debug(f"Writing AFI - UID: {uid}, AFI: {afi}")
        
        if not uid:
            logger.warning("UID is required but not provided")
            return {
                'error': True,
                'message': "UID is required"
            }
        if afi is None:
            logger.warning("AFI value is required but not provided")
            return {
                'error': True,
                'message': "AFI value is required"
            }
            
        # Write AFI to tag
        result = reader.write_afi(uid, afi)
        if result is None:
            logger.error("Failed to write AFI")
            return {
                'error': True,
                'message': "Failed to write AFI"
            }
            
        logger.info(f"Successfully wrote AFI for UID: {uid}")
        return {
            'error': False,
            'message': "AFI written successfully"
        }
    except Exception as e:
        logger.error(f"Error writing AFI: {str(e)}", exc_info=True)
        return {
            'error': True,
            'message': f"Error writing AFI: {str(e)}"
        }

@app.route('/get-tag-status', methods=['POST'])
def get_tag_status():
    global reader
    logger.info("Getting tag status")
    try:
        if reader is None:
            logger.warning("Device not opened")
            return {
                'error': True,
                'message': "Device not opened. Please open device first."
            }
            
        # Get UID from request
        data = request.get_json()
        uid = data.get('uid')
        
        logger.debug(f"Getting tag status for UID: {uid}")
        
        if not uid:
            logger.warning("UID is required but not provided")
            return {
                'error': True,
                'message': "UID is required"
            }
            
        # Get tag status
        status = reader.get_tag_status(uid)
        if status is None:
            logger.error("Failed to get tag status")
            return {
                'error': True,
                'message': "Failed to get tag status"
            }
            
        logger.info(f"Successfully retrieved tag status for UID: {uid}, Status: {status}")
        return {
            'error': False,
            'status': status,
            'message': "Tag status retrieved successfully"
        }
    except Exception as e:
        logger.error(f"Error getting tag status: {str(e)}", exc_info=True)
        return {
            'error': True,
            'message': f"Error getting tag status: {str(e)}"
        }

if __name__ == '__main__':
    logger.info("Starting RFID Web Application")
    app.run(host='0.0.0.0', port=5000, debug=True)
